package com.wondertek.poms.core.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wondertek.poms.common.constant.Constants;
import com.wondertek.poms.common.service.impl.ServiceImpl;
import com.wondertek.poms.common.utils.CopyUtils;
import com.wondertek.poms.common.utils.StringUtil;
import com.wondertek.poms.core.service.IContentBaseFeeService;
import com.wondertek.poms.core.service.IContentFeeService;
import com.wondertek.poms.core.service.IEquityNodeService;
import com.wondertek.poms.core.service.IPomsExportLogService;
import com.wondertek.poms.core.service.IPrdFreeFlowService;
import com.wondertek.poms.core.service.IPrdInfoService;
import com.wondertek.poms.dao.po.ContentBaseFee;
import com.wondertek.poms.dao.po.ContentFee;
import com.wondertek.poms.dao.po.EquityNode;
import com.wondertek.poms.dao.po.PrdFreeFlow;
import com.wondertek.poms.dao.po.PrdInfo;
import com.wondertek.poms.dao.po.SystemConfig;
import com.wondertek.poms.dao.repo.IPrdInfoDao;
import com.wondertek.poms.dao.repo.ISystemConfigDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.io.File;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chenjijiang
 * @description
 */
@Slf4j
@Service
public class PrdInfoServiceImpl extends ServiceImpl<PrdInfo, Long> implements IPrdInfoService {
	@Autowired
	private IPrdInfoDao prdInfoDao;
	@Autowired
	private ISystemConfigDao systemConfigDao;
	@Autowired
	private IContentBaseFeeService contentBaseFeeService;
	@Autowired
	private IContentFeeService contentFeeService;
	@Autowired
	private IPomsExportLogService pomsExportLogService;
	@Autowired
	private IPrdFreeFlowService prdFreeFlowService;
	@Autowired
	private IEquityNodeService equityNodeService;


	@Override
	public PrdInfo deleteLogic(Long id) {
		return null;
	}

	@Override
	public PrdInfo merge(PrdInfo model) {
		PrdInfo info = jpaRepository.getOne(model.getPrdInfoId());
		CopyUtils.copyProperties(model, info);
		return jpaRepository.save(info);
	}

	@Override
	public Page<PrdInfo> findAll(PrdInfo entity, int page, int rows, String order, String column) {
		Pageable pageable = getPageable(page - 1, rows, column, order);
		Specification<PrdInfo> specification = getWhereClause(entity);
		return prdInfoDao.findAll(specification, pageable);
	}

	private Specification<PrdInfo> getWhereClause(PrdInfo entity) {
		return (Specification<PrdInfo>) (root, query, cb) -> {
			List<Predicate> predicate = new ArrayList<>();
			if (entity.getPrdInfoId() != null) {
				predicate.add(cb.equal(root.get("prdInfoId"), entity.getPrdInfoId()));
			}
			if (StringUtils.isNotBlank(entity.getName())) {
				predicate.add(cb.like(root.get("name"), "%" + entity.getName() + "%"));
			}
			if (entity.getIsPublish() != null) {
				predicate.add(cb.equal(root.get("isPublish"), entity.getIsPublish()));
			}
			Predicate[] pre = new Predicate[predicate.size()];
			return query.where(predicate.toArray(pre)).getRestriction();
		};
	}

	@Override
	public Map<String, List<List<PrdInfo>>> getNotPackagePrdInfo() {
		Map<String, List<List<PrdInfo>>> piMap = new HashMap<>();
		List<PrdInfo> prdInfoList = prdInfoDao.getNotPackagePrdInfo();
		if (prdInfoList != null && prdInfoList.size() > 0) {
			Map<Long, PrdInfo> prdInfoMap = prdInfoList.stream()
					.collect(Collectors.toMap(PrdInfo::getPrdInfoId, pi -> pi));
			List<PrdInfo> normalList = new ArrayList<PrdInfo>();
			Set<PrdInfo> specialList = new HashSet<PrdInfo>();
			for (PrdInfo prdInfo : prdInfoList) {
				if (prdInfo.getParentPrdInfo() != null) {
					if (prdInfo.getProductInfoPackageId() == null) {
						specialList.add(prdInfo);
						PrdInfo ppi = prdInfoMap.get(prdInfo.getParentPrdInfo());
						specialList.add(ppi);
					}
				}
			}
			for (PrdInfo prdInfo : prdInfoList) {
				if (!specialList.contains(prdInfo)) {
					normalList.add(prdInfo);
				}
			}
			List<List<PrdInfo>> no = new ArrayList<List<PrdInfo>>();
			no.add(normalList);
			piMap.put("normal", no);

			List<PrdInfo> firstPrdInfo = new ArrayList<PrdInfo>();
			for (PrdInfo pi : specialList) {
				if (pi.getParentPrdInfo() != null) {
					boolean isMatch = false;
					for (PrdInfo pi2 : specialList) {
						if (pi2.getParentPrdInfo() != null
								&& pi2.getParentPrdInfo().equals(pi.getPrdInfoId())) {
							isMatch = true;
							break;
						}
					}
					if (!isMatch) {
						firstPrdInfo.add(pi);
					}
				}
			}
			List<List<PrdInfo>> special = new ArrayList<>();
			if (firstPrdInfo.size() > 0) {
				for (PrdInfo pi : firstPrdInfo) {
					List<PrdInfo> l = new ArrayList<>();
					l = recursivePrdInfo(l, pi, 0, prdInfoMap);
					special.add(l);
				}
			}
			piMap.put("special", special);
			log.info("主流程|获取普通包：" + normalList.size() + "|父子包：" + special.toString());
		}
		return piMap;
	}


	//为避免死递归，超过5次就退出
	private static List<PrdInfo> recursivePrdInfo(List<PrdInfo> l, PrdInfo pi, int times, Map<Long, PrdInfo> prdInfoMap) {
		++times;
		if (times > 5) {
			return l;
		}
		l.add(pi);
		if (pi.getParentPrdInfo() != null) {
			PrdInfo ppi = prdInfoMap.get(pi.getParentPrdInfo());
			recursivePrdInfo(l, ppi, times, prdInfoMap);
		}
		return l;
	}

	public static void main(String[] args) {
		List<PrdInfo> specialList = new ArrayList<PrdInfo>();
		PrdInfo pi1 = new PrdInfo();
		pi1.setPrdInfoId(1l);
		pi1.setParentPrdInfo(null);
		PrdInfo pi22 = new PrdInfo();
		pi22.setPrdInfoId(11l);
		pi22.setParentPrdInfo(1l);
		PrdInfo pi3 = new PrdInfo();
		pi3.setPrdInfoId(111l);
		pi3.setParentPrdInfo(11l);

		PrdInfo pi4 = new PrdInfo();
		pi4.setPrdInfoId(2l);
		pi4.setParentPrdInfo(null);
		PrdInfo pi5 = new PrdInfo();
		pi5.setPrdInfoId(22l);
		pi5.setParentPrdInfo(2l);
		specialList.add(pi22);
		specialList.add(pi3);
		specialList.add(pi1);
		specialList.add(pi4);
		specialList.add(pi5);
		Map<Long, PrdInfo> prdInfoMap = specialList.stream()
				.collect(Collectors.toMap(PrdInfo::getPrdInfoId, pi -> pi));


		List<PrdInfo> firstPrdInfo = new ArrayList<PrdInfo>();
		for (PrdInfo pi : specialList) {
			if (pi.getParentPrdInfo() != null) {
				boolean isMatch = false;
				for (PrdInfo pi2 : specialList) {
					if (pi2.getParentPrdInfo() != null
							&& pi2.getParentPrdInfo().equals(pi.getPrdInfoId())) {
						isMatch = true;
						break;
					}
				}
				if (!isMatch) {
					firstPrdInfo.add(pi);
				}
			}
		}
		List<List<PrdInfo>> special = new ArrayList<>();
		if (firstPrdInfo.size() > 0) {
			for (PrdInfo pi : firstPrdInfo) {
				List<PrdInfo> l = new ArrayList<>();
				l = recursivePrdInfo(l, pi, 0, prdInfoMap);
				special.add(l);
			}
		}

		System.out.println(special);
	}

	@Override
	public List<PrdInfo> findPrdInfoInPackageId(Long productInfoPackageId, int publishStatus) {
		return prdInfoDao.findPrdInfoInPackageId(productInfoPackageId, publishStatus);
	}

	@Override
	public PrdInfo findByPrdInfoId(Long prdInfoId) {
		return prdInfoDao.findByPrdInfoId(prdInfoId);
	}

	/**
	 * @param map 数据
	 * @return 同步数据到能力
	 */
	@Override
	public Map<String, Object> syncPowerData(Map<String, Object> map) {

		SystemConfig urlConfig = systemConfigDao.findByCkey("queryProductInfo");
		Map<String, Object> resultMap = new HashMap<>();
		ObjectMapper mapper = new ObjectMapper();
		try {
			HttpResponse response = HttpUtil.createPost(urlConfig.getValue()).body(mapper.writeValueAsString(map),
					"application/json").execute();
			Map<String, String> rtMqp = mapper.readValue(response.body(), Map.class);
			String code = rtMqp.get("code");
			if (!"0".equals(code)) {
				log.info("#########同步能力数据失败#########");
				resultMap.put("code", 1);
				resultMap.put("msg", "同步能力失败");
				return resultMap;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		log.info("#########同步能力数据成功#########");
		resultMap.put("code", 0);
		resultMap.put("msg", "同步能力成功");
		return resultMap;
	}

	@Override
	public Map<String, Object> withdrawPrdInfo(PrdInfo prdInfo, SystemConfig basePathsConfig) {
		Long id = prdInfo.getPrdInfoId();
		String[] basePaths = basePathsConfig.getValue().split(",");
		for (String path : basePaths) {
			//存在就删除xml文件
			if (StringUtils.isNotBlank(path)) {
				File f = new File(path, id + ".xml");
				if (f.exists()) {
					f.delete();
				}
			}
		}
		log.info("==修改portal数据库数据  开始==");
		Date publishTime = new Date();
		pomsExportLogService.updateLog("2", prdInfo.getPrdInfoId(), "0", publishTime);
		log.info("==修改portal数据库数据  结束==");
		Map<String, Object> delMap = new HashMap<String, Object>();
		delMap.put("operation", Constants.SYNC_DELETE);
		delMap.put("id", id);
		log.info("同步能力商品包:" + id);
		return syncPowerData(delMap);
	}

	@Override
	public int updateIsPublish(Integer status, List<Long> prdInfoIds) {
		return prdInfoDao.updateIsPublish(status, prdInfoIds);
	}

	@Override
	public Map<String, Object> publishPrdInfo(PrdInfo prdInfo, SystemConfig basePathsConfig, SystemConfig urlConfig, Map<String, Object> resultMap, List<String> prdInfoNameList) {
		String format = "yyyy-MM-dd HH:mm:ss";
		Map<String, Object> root = new HashMap<String, Object>();
		root.put("Version", "1.0.0");
		root.put("prdInfoId", prdInfo.getPrdInfoId());
		if (prdInfo.getName() != null && !prdInfoNameList.contains(prdInfo.getName())) {
			root.put("parentPrdInfo", prdInfo.getParentPrdInfo());
		}
		root.put("name", prdInfo.getName());
		root.put("alias", prdInfo.getAlias());
		root.put("description", prdInfo.getDescription());
		root.put("type", StringUtil.nullToString(prdInfo.getType()));
		root.put("bcId", StringUtil.nullToString(prdInfo.getBcId()));
		root.put("spId", StringUtil.nullToString(prdInfo.getSpId()));
		root.put("prdInfoType", StringUtil.nullToString(prdInfo.getPrdInfoType()));
		root.put("createTime", prdInfo.getCreateTime() != null ? DateUtil.format((prdInfo.getCreateTime()), format) : "");
		root.put("updateTime", prdInfo.getUpdateTime() != null ? DateUtil.format((prdInfo.getUpdateTime()), format) : "");
		root.put("pubTime", prdInfo.getPubTime() != null ? DateUtil.format((prdInfo.getPubTime()), format) : "");
		root.put("monthType", StringUtil.nullToString(prdInfo.getMonthType()));
		root.put("numberType", StringUtil.nullToString(prdInfo.getNumberType()));
		root.put("freeType", StringUtil.nullToString(prdInfo.getFreeType()));

		//权益
		String equityIds = prdInfo.getEquityId();
		List<Map<String, Object>> equities = new LinkedList<Map<String, Object>>();

		if (!StringUtil.isNullStr(equityIds)) {
			String[] arrayEquityId = equityIds.split(",");
			for (String equityId : arrayEquityId) {
				Map<String, Object> equityMap = new HashMap<String, Object>();
				EquityNode equityNode = equityNodeService.findById(StringUtil.nullToLong(equityId));
				if (equityNode != null) {
					equityMap.put("equityId", equityNode.getEquityNodeId());
				}
				equities.add(equityMap);
			}
		}
		root.put("equities", equities);

		//促销信息
		HashSet<Long> channelPkgSet = new HashSet<Long>();//基本计费与促销计费渠道包set
		List<Map<String, String>> sales = new LinkedList<Map<String, String>>();
		Map<Long, List> channelPkgM = new HashMap<Long, List>();//渠道包促销计费
		Map<String, String> m = new HashMap<String, String>();
		List<ContentFee> cfs = contentFeeService.findByTypeAndPomsId(1, prdInfo.getPrdInfoId());
		if (cfs != null && cfs.size() > 0) {
			for (int i = 0; i < cfs.size(); i++) {
				ContentFee cf = cfs.get(i);
				if (cf.getChannelPackageId() == null) {//非渠道促销放这里
					Map<String, String> smp = new HashMap<String, String>();
					smp.put("salesProductId", StringUtil.null2Str(cf.getSaleProductId()));
					smp.put("salesCategory", StringUtil.null2Str(cf.getSaleCategory()));
					smp.put("salesStartTime", cf.getStartTime());
					smp.put("salesEndTime", cf.getEndTime());
					smp.put("salesDiscount", cf.getDiscount());
					//权益
					smp.put("equityId", cf.getEquityId());
					sales.add(smp);
				} else {//渠道促销
					List<Map<String, String>> channelSales;
					if (channelPkgM.containsKey(cf.getChannelPackageId())) {
						channelSales = channelPkgM.get(cf.getChannelPackageId());
					} else {
						channelSales = new LinkedList<Map<String, String>>();
					}

					Map<String, String> smp = new HashMap<String, String>();
					smp.put("salesProductId", StringUtil.null2Str(cf.getSaleProductId()));
					smp.put("salesCategory", StringUtil.null2Str(cf.getSaleCategory()));
					smp.put("salesStartTime", cf.getStartTime());
					smp.put("salesEndTime", cf.getEndTime());
					smp.put("salesDiscount", cf.getDiscount());

					smp.put("equityId", cf.getEquityId());

					channelSales.add(smp);
					channelPkgM.put(cf.getChannelPackageId(), channelSales);

					channelPkgSet.add(cf.getChannelPackageId());
				}
			}
		}
		root.put("salesPromotions", sales);

		//渠道基本计费
		Map<Long, Map<String, String>> basePkgM = new HashMap<Long, Map<String, String>>();//渠道包基本计费
		List<ContentBaseFee> baseFees = contentBaseFeeService.findByPrdInfoId(prdInfo.getPrdInfoId());//包含基本30天包月、渠道普通计费、渠道30天包月
		List<ContentBaseFee> otherFees = new ArrayList<ContentBaseFee>();//30天包月产品
		Map<Long, List<ContentBaseFee>> otherFeesM = new HashMap<Long, List<ContentBaseFee>>();//渠道包30天包月产品计费
		if (baseFees != null && baseFees.size() > 0) {
			for (ContentBaseFee fee : baseFees) {
				if (fee.getChannelPackageId() == null) {
					otherFees.add(fee);
				} else {
					Map<String, String> bf = new HashMap<String, String>();
					String productIds = "";
					if (basePkgM.containsKey(fee.getChannelPackageId())) {
						bf = basePkgM.get(fee.getChannelPackageId());
					}
					if ("0".equals(fee.getOrderFlag())) {//包月
						productIds = fee.getProductId();
						if (!StringUtil.isNullStr(bf.get("monthType"))) {
							productIds += "," + bf.get("monthType");
						}
						bf.put("monthType", productIds);
					} else if ("1".equals(fee.getOrderFlag())) {//按次
						productIds = fee.getProductId();
						if (!StringUtil.isNullStr(bf.get("numberType"))) {
							productIds += "," + bf.get("numberType");
						}
						bf.put("numberType", productIds);
					} else if ("7".equals(fee.getOrderFlag())) {//免费
						productIds = fee.getProductId();
						if (!StringUtil.isNullStr(bf.get("freeType"))) {
							productIds += "," + bf.get("freeType");
						}
						bf.put("freeType", productIds);
					} else {
						if (otherFeesM.containsKey(fee.getChannelPackageId())) {
							List<ContentBaseFee> l = otherFeesM.get(fee.getChannelPackageId());
							l.add(fee);
//												otherPkgM.put(fee.getChannelPackageId(), l);
						} else {
							List<ContentBaseFee> l = new ArrayList<ContentBaseFee>();
							l.add(fee);
							otherFeesM.put(fee.getChannelPackageId(), l);
						}
					}
					basePkgM.put(fee.getChannelPackageId(), bf);
					channelPkgSet.add(fee.getChannelPackageId());
				}
			}
		}

		if (otherFees.size() > 0) {
			for (ContentBaseFee fee : otherFees) {
				if (StringUtil.isNullStr(root.get("otherType"))) {
					root.put("otherType", fee.getProductId());
				} else {
					root.put("otherType", root.get("otherType") + "," + fee.getProductId());
				}
			}
		}

		List<Map<String, Object>> channelPkgs = new LinkedList<Map<String, Object>>();
		if (channelPkgSet.size() > 0) {
			Iterator<Long> itr = channelPkgSet.iterator();
			while (itr.hasNext()) {
				Long pkgId = itr.next();
				Map<String, Object> pkgM = new HashMap<String, Object>();
				pkgM.put("id", pkgId);
				if (basePkgM.containsKey(pkgId)) {
					Map<String, String> bf = basePkgM.get(pkgId);
					pkgM.put("monthType", StringUtil.nullToString(bf.get("monthType")));
					pkgM.put("numberType", StringUtil.nullToString(bf.get("numberType")));
					pkgM.put("freeType", StringUtil.nullToString(bf.get("freeType")));
				}
				if (channelPkgM.containsKey(pkgId)) {
					pkgM.put("salesPromotions", channelPkgM.get(pkgId));
				}
				if (otherFeesM.containsKey(pkgId)) {
//										pkgM.put("otherFees", otherFeesM.get(pkgId));
					for (ContentBaseFee fee : otherFeesM.get(pkgId)) {
						if (StringUtil.isNullStr(pkgM.get("otherType"))) {
							pkgM.put("otherType", fee.getProductId());
						} else {
							pkgM.put("otherType", pkgM.get("otherType") + "," + fee.getProductId());
						}
					}
				}
				channelPkgs.add(pkgM);
			}
		}
		root.put("channelPkgs", channelPkgs);
		//流量限免   CONTENT.freeFlowLists
		Map<String, String> parMap = new HashMap<String, String>();
		parMap.put("pomsType", "1");
		parMap.put("pomsId", StringUtil.nullToString(prdInfo.getPrdInfoId()));
		List<PrdFreeFlow> freeFlowList = prdFreeFlowService.findAllByPomsIdAndPomsType(prdInfo.getPrdInfoId(), 1);
		PrdFreeFlow pff = new PrdFreeFlow();
		if (freeFlowList.size() > 0) {
			pff = freeFlowList.get(0);
		}
		root.put("freeFlow", pff);

		Map<String, Object> metaMap = new HashMap<String, Object>();
		metaMap.put("PRDINFO", root);

		HashMap<String, Object> paramMap = new HashMap<String, Object>(root);
		paramMap.remove("Version");
		paramMap.put("version", "1.0.0");
		paramMap.remove("channelPkgs");
		paramMap.put("channelPkgsProduct", channelPkgs);
		paramMap.put("productFirstId", StringUtil.nullToString(prdInfo.getFirstProductInfoPackageId()));
		paramMap.put("productSecondId", StringUtil.nullToString(prdInfo.getProductInfoPackageId()));
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("id", prdInfo.getPrdInfoId());
		map.put("operation", Constants.SYNC_PUBLISH);
		map.put("data", paramMap);
		ObjectMapper mapper = new ObjectMapper();
		try {
			HttpResponse response = HttpUtil.createPost(urlConfig.getValue()).body(mapper.writeValueAsString(map),
					"application/json").execute();
			Map<String, String> rtMqp = mapper.readValue(response.body(), Map.class);
			String code = rtMqp.get("code");
			if (!"0".equals(code)) {
				log.info("商品包发布同步能力失败");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		log.info("商品包发布同步能力成功");
		return metaMap;
	}


	@Override
	public int updatePrdInfoPublish(Integer status, LocalDateTime now, List<Long> list) {
		return prdInfoDao.updatePrdInfoPublish(status, now, list);
	}

	@Override
	public List<PrdInfo> findAllByProductInfoPackageId(Long firstProductInfoPackageId) {
		if (firstProductInfoPackageId == null) {
			return new ArrayList<>();
		}
		return prdInfoDao.findAllByProductInfoPackageId(firstProductInfoPackageId);
	}

	@Override
	public List<PrdInfo> findAllTargetPrdInfo(Long prdInfoId) {
		return prdInfoDao.findAllTargetPrdInfo(prdInfoId);
	}

	@Override
	public List<PrdInfo> findAllPublishedPrdInfo() {
		return prdInfoDao.findAllPublishedPrdInfo();
	}

	@Override
	public PrdInfo getByPrdInfoIdAndSystemFlag(Long prdInfoId) {
		return prdInfoDao.getByPrdInfoIdAndSystemFlag(prdInfoId);
	}

	@Override
	public List<PrdInfo> findPrdInfoByIsPublish(int publishStatus) {
		return prdInfoDao.findPrdInfoByIsPublish(publishStatus);
	}

	@Override
	public List<PrdInfo> findForBlackWhite(int publishStatus) {
		List<PrdInfo> list = prdInfoDao.findPrdInfoByIsPublish(publishStatus);
		List<PrdInfo> list1 = prdInfoDao.findAllParentPrdInfo(publishStatus);
		//父子包产品id
		Set<String> set=new LinkedHashSet<>();
		List<Long> son=new LinkedList<>();
		for (PrdInfo prdInfo:list1) {
			set.add(prdInfo.getPrdInfoId().toString());
			son.add(prdInfo.getParentPrdInfo());
		}
		List<PrdInfo> list2 = prdInfoDao.findParentPrdInfo(publishStatus,son);
		List<Long> dad=new LinkedList<>();

		for (PrdInfo prdInfo:list2) {
			set.add(prdInfo.getPrdInfoId().toString());
			set.add(prdInfo.getParentPrdInfo().toString());
			dad.add(prdInfo.getParentPrdInfo());
		}
		List<PrdInfo> list3 = prdInfoDao.findParentPrdInfo(publishStatus,dad);
		if(list3.size()!=0){
			log.error("父子包中爷爷包关系错误.");
		}
		String judge=",";
		for (String str:set) {
			judge+=str+",";
		}
		for (int i = list.size()-1; i >-1 ; i--) {
			if(judge.contains(","+list.get(i).getPrdInfoId()+",")){
				list.remove(i);
			}
		}
		return list;
	}

}
